<script setup>

  import { defineProps, onBeforeUnmount, onMounted, ref, watch } from "vue";
  import commonApi from '@/api/common/index.js';
  import userApi from '@/api/user/index.js';
  import ResponseUtil from "@/utils/ResponseUtil.js";

  let props = defineProps({
    is_open: Boolean,
    get_data: Function,
    callback: Function
  });

  let is_close = ref(true);

  let parent_data = {};
  let target_last = ref('');
  let target_address = ref('');
  let message = ref('');

  watch(props, () => {
    is_close.value = !props.is_open;

    if (props.is_open) {
      parent_data = props.get_data();
      target_address.value = target_last.value = parent_data.target.includes("@") ? '邮箱':'手机号码';
      target_last.value = parent_data.target.includes("@") ?
          parent_data.target.substring(parent_data.target.indexOf('@') - 5, parent_data.target.indexOf('@') - 1)
          : parent_data.target.substring(parent_data.target.length - 4, parent_data.target)


      message.value = '验证码已发送值您尾号为 ' + target_last.value + ' 的' + target_address.value + '中，验证码三分钟内有效，请您注意查收~';
    }
  })


  // 获取所有的验证码输入 input 元素
  let inputElementList = document.getElementsByClassName('verify-code-number');

  // 验证码验证请求提醒
  let verify_code_request_message = ref('');

  // 验证码验证结果，0 默认，1成功，-1失败，777 请求中
  let verify_result = ref(0);

  // 是否输入了所有验证码
  let is_enter = ref(false);

  // 判断是否为首次提交验证码
  let is_first_submit = true;

  // 是否禁用文本框
  let is_disabled = ref(false);

  // 验证码实际存储集合
  let verify_code_number_list = ref([
    { value: '' },
    { value: '' },
    { value: '' },
    { value: '' },
    { value: '' },
    { value: '' },
  ]);

  // 解决 watch 监听响应式变量，old new 都是更新后的内容
  let verify_code_number_list_bak = [
    { value: '' },
    { value: '' },
    { value: '' },
    { value: '' },
    { value: '' },
    { value: '' },
  ]

  watch(
      verify_code_number_list,
      new_values => verify_code_number_update(new_values),
      { deep : true }
  )

  // 文本框内容产生变化后的回调函数
  const verify_code_number_update = (new_values) => {
    // 只要监听掉变化，则将文本框异常效果需求
    verify_result.value = 0;
    verify_code_request_message.value = '';

    // 内容发生变化后的前置处理逻辑，主要处理逻辑
    verify_code_number_update_before(new_values);

    // 判断是否输入完毕，输入完毕触发自定请求 或 登录按钮显示，并将光标焦点移除
    verify_code_number_update_after();
  }



  const verify_code_number_update_before = (new_values) => {

    // 阻止响应式重新触发，如果集合内容与备份完全一致时，直接返回
    let is_same = true;
    verify_code_number_list_bak.forEach((x, index_inner) => {
      if (x.value !== new_values[index_inner].value) {
        is_same = false;
      }
    })
    if (is_same) return;

    // 记录存在变化的数据信息
    // index 索引、value 值、type 类型（1删除，2新增或修改）
    let exist_change = {
      type: -1,
      index: -1,
      value: ''
    }

    // 遍历验证码输入的旧值集合，找到发生变化的输入框以及值
    for (let inner_index = 0; inner_index < verify_code_number_list_bak.length; inner_index++) {

      // 判断旧值集合与新值集合，相同下标下的值是否存在变化
      if (verify_code_number_list_bak[inner_index].value !== new_values[inner_index].value) {

        // 记录发生变化的数据信息
        exist_change.type = new_values[inner_index].value === '' ? 1 : 2;
        exist_change.index = inner_index;
        exist_change.value = new_values[inner_index].value;

        // 结束循环
        break;
      }

    }

    // 判断是否有发送变化，未发生变化则直接结束
    if (exist_change.index === -1) return;

    // 判断是否为删除操作
    if (exist_change.type === 1) {
      // 替换备份集合旧值为新值
      verify_code_number_list_bak[exist_change.index].value = exist_change.value;

      // 校验文本框是否为尾末的验证码输入文本框 && 校验当前文本框的后一个文本框是否有值
      if (!(exist_change.index === inputElementList.length - 1) && verify_code_number_list.value[exist_change.index + 1].value !== '') {
        // 索引 + 1，使得其删除后保持原位
        exist_change.index += 1;
      }


      // 判断是光标焦点是否为首个文本框，首个文本框不做任何操作，非个文本框，光标前移一位
      inputElementList[exist_change.index === 0 ? 0 : exist_change.index - 1].focus();
    }

    // 判断是否为新增或修改操作
    if (exist_change.type === 2) {
      // 将输入的新值去除空格
      let real_value =  exist_change.value.replace(' ', '');

      // 使用去除空格后的新值重写与备份旧值进行是否相等的判断，并进行新值非''判断，避免非法值的输入
      if (real_value === verify_code_number_list_bak[exist_change.index].value || real_value === '') {
        // 去除空格后值相同表示输入了空格，非法输入，将旧值反赋到实际值
        verify_code_number_list.value[exist_change.index].value = real_value;

        // 非法输入空格，结束执行
        return;
      }

      // 判断是否为多值操作
      let is_more_enter = exist_change.value.length > 1;

      // 非多值操作，单值新增或修改操作
      if (!is_more_enter) {
        // 替换备份集合旧值为新值
        verify_code_number_list_bak[exist_change.index].value = exist_change.value;

        // 判断是光标焦点是否为末尾，末尾文本框不做任何操作，非末尾文本框，光标后移一位
        inputElementList[exist_change.index === inputElementList.length - 1 ? exist_change.index : exist_change.index + 1].focus();
      }

      // 多值操作
      if (is_more_enter) {
        // 将多个值去空格，拆分为数组
        let splits = exist_change.value.replace(' ', '').split('');

        // 当前索引所在文本框对应的值，无条件进行更新（新旧全部更新）
        verify_code_number_list_bak[exist_change.index].value = splits[0];
        verify_code_number_list.value[exist_change.index].value = splits[0];

        // 开始拆分后的值
        for (let i = 1; i < splits.length; i++) {
          // 长度超出后结束修改值
          if (i + exist_change.index === verify_code_number_list.value.length) {
            break;
          }

          // 覆盖原有值（新/旧值）
          verify_code_number_list_bak[exist_change.index + i].value = splits[i];
          verify_code_number_list.value[exist_change.index + i].value = splits[i];

          // 光标降低置为下标后一位，超出最大长度则无操作
          inputElementList[exist_change.index + i === inputElementList.length - 1 ? exist_change.index + i : exist_change.index + i + 1].focus();
        }
      }

    }

  }
  const verify_code_number_update_after = () => {
    let isAllWrite = true;

    // 校验内容是否输入完成
    verify_code_number_list.value.forEach(x => {
      if (x.value === '') {
        isAllWrite = false;
      }
    })

    // 未完成驶入则将提交按钮隐藏并跳出
    if (!isAllWrite) {
      is_enter.value = false;
      return;
    }

    // 完成则使光标失去焦点
    for (let inputElement of inputElementList) {
      if (inputElement === document.activeElement) {
        inputElement.blur();
        break;
      }
    }

    // 判断是否为首次提交验证码，首次提交自动发送请求
    if (is_first_submit) {
      // 首次提交后，将首次提交标识变量设置为 false
      is_first_submit = false;

      // 发起验证码校验请求
      check_verify_code();

    } else {
      // 非首次提交则显示提交按钮，由用户手动提交
      is_enter.value = true;
    }

  }

  const check_verify_code = () => {
    // 设置文本框进入等待样式
    verify_result.value = 777;
    is_disabled.value = true;
    setTimeout(() => {
      if (verify_result.value === 777) {
        verify_code_request_message.value = '正在请求服务器进行验证码验证，请稍后~';
      }
    }, 500);

    // 获取验证码字符串
    let verify_code = '';
    verify_code_number_list.value.forEach(x => {
      verify_code += x.value;
    });

    // 自动发起请求，获取验证码
    userApi.updateEmailOrMobileVerifyCodeCheck(parent_data.workType, parent_data.target, verify_code).then(response => {
      ResponseUtil.data(response).dispose(response => {
        if (response.code === '200') {
          verify_result.value = 1;
          verify_code_request_message.value = '验证码正确，即将完成验证~';
          setTimeout(() => {
            response.data.value;
            props.callback(1, parent_data.index, response.data.value);
            reset_all_data();
          }, 1000);
        } else {
          verify_result.value = -1;
          is_disabled.value = false;
          verify_code_request_message.value = response.message;
        }
      })
    })
  }


  // 重置验证码
  const reset_verify_code = () => {
    verify_code_number_list.value = [
      { value: '' },
      { value: '' },
      { value: '' },
      { value: '' },
      { value: '' },
      { value: '' },
    ];

    verify_code_number_list_bak = [
      { value: '' },
      { value: '' },
      { value: '' },
      { value: '' },
      { value: '' },
      { value: '' },
    ]
  }

  const close_click = () => {
    is_close.value = true;
    props.callback(0);
  }


  onMounted(() => {
    // 监听键盘按下
    window.addEventListener('keydown', handleKeyDown);
  })


  onBeforeUnmount(() => {
    // 取消监听键盘按下
    window.removeEventListener('keydown', handleKeyDown);
  })

  const handleKeyDown = (event) => {
    // 起始索引
    let index = -1;

    for (let i = 0; i < inputElementList.length; i++) {
      if (inputElementList[i] === document.activeElement) {
        index = i;
        break;
      }
    }

    if (index === -1) return;

    if (event.keyCode === 37) {
      event.preventDefault();
      inputElementList[index === 0 ? 0 : index - 1].focus();
    } else if (event.keyCode === 39) {
      event.preventDefault();
      inputElementList[index === inputElementList.length - 1 ? inputElementList.length - 1 : index + 1].focus();
    }
  }

  // 重置组件内容的所有数据
  const reset_all_data = () => {
    setTimeout(() => {
      verify_result.value = 0; // 验证码文本框样式置恢复默认状态
      verify_code_request_message.value = '';  // 验证码文本框样式上方提示信息恢复默认状态

      is_first_submit = true; // 验证码首次提交标识恢复为默认状态

      is_disabled.value = false; // 验证码文本框禁用恢复为默认状态

      // 验证码值恢复为默认状态
      is_enter.value = false;
      verify_code_number_list.value = [
        { value: '' },
        { value: '' },
        { value: '' },
        { value: '' },
        { value: '' },
        { value: '' },
      ];
      verify_code_number_list_bak = [
        { value: '' },
        { value: '' },
        { value: '' },
        { value: '' },
        { value: '' },
        { value: '' },
      ];
    }, 600);
  }


</script>

<template>
  <div :class="['verify-code-alert-basic', is_close ? 'common-opacity-2-animation':'common-opacity-1-animation']">
    <div class="verify-code-basic">

      <div class="verify-code-alert-close" @click="close_click">
        X
      </div>

      <div class="verify-code-header">
        <div class="title">请输入验证码，校验验证码</div>
        <div class="remark">{{ message }}</div>
      </div>

      <div :class="['verify-code-message', verify_result === 0 ? 'verify-code-message-text-default':'',
        verify_result === 1 ? 'verify-code-message-text-success':'', verify_result === -1 ? 'verify-code-message-text-fail':'',
        verify_result === 777 ? 'verify-code-message-text-wait':'']">{{ verify_code_request_message }}</div>

      <div class="verify-code-subject">
        <input type="text" v-for="data in verify_code_number_list" v-model="data.value" :disabled="is_disabled"
               :class="['verify-code-number', verify_result === 0 ? 'verify-code-input-border-default':'',
               verify_result === 1 ? 'verify-code-input-border-success':'', verify_result === -1 ? 'verify-code-input-border-fail':'',
               verify_result === 777 ? 'verify-code-input-border-default':'']"/>
      </div>

      <div :class="['verify-code-button-basic', is_enter ? 'common-opacity-1-animation':'common-opacity-2-animation']">
        <button class="submit" @click="check_verify_code">提交</button>
        <button class="reset" @click="reset_verify_code">重置</button>
      </div>

    </div>
  </div>
</template>

<style scoped>
  .verify-code-alert-basic {
    width: 100vw;
    height: 100vh;
    position: fixed;
    left: 0;
    top: 0;
    background-color: rgb(0, 0, 0, .2);
    z-index: 10;
  }

  .verify-code-alert-close {
    width: 24px;
    height: 24px;
    position: absolute;
    right: 24px;
    display: flex;
    justify-content: center;
    align-items: center;
    border-radius: 3px;
    user-select: none;
    color: rgb(58, 58, 58);
    transition: background-color .3s;
  }
  .verify-code-alert-close:hover {
    background-color: #e1e1e1;
    cursor: pointer;
  }

  .verify-code-basic {
    width: 700px;
    height: 380px;
    padding: 25px 32px;
    border-radius: 20px;
    background-color: rgb(245, 245, 245);
    position: absolute;
    left: calc(50% - 350px - 32px);
    top: 18%;
    box-shadow: 0 0 15px 5px rgba(0, 0, 0, .1);
  }

  .verify-code-header {
    width: 100%;
    overflow: hidden;
  }
  .verify-code-header .title {
    font-size: 30px;
    margin: 3px 0;
    user-select: none;
  }
  .verify-code-header .remark {
    color: rgb(128, 128, 128);
    font-size: 12px;
    margin: 5px 0;
    user-select: none;
  }

  .verify-code-message {
    width: 100%;
    height: 20px;
    margin: 66px 0 12px 0;
    text-indent: 36px;
    font-size: 14px;
  }

  .verify-code-subject {
    width: 100%;
    overflow: hidden;
    display: flex;
    justify-content: center;
  }
  .verify-code-subject .verify-code-number {
    margin: 0 15px;
    width: 80px;
    height: 80px;
    background-color: white;
    text-align: center;
    outline: none;
    border-radius: 12px;
    font-size: 30px;
    transition: border-bottom-color .3s, border-right-color .3s, border-left-color .3s, border-top-color .3s;
  }

  .verify-code-input-border-default {
    border: 1px solid #f5f5f5;
  }
  .verify-code-input-border-success {
    border: 1px solid #67c23a;
  }
  .verify-code-input-border-fail {
    border: 1px solid #f56c6c;
  }

  .verify-code-message-text-default {
    color: #f5f5f5;
  }
  .verify-code-message-text-success {
    color: #67c23a;
  }
  .verify-code-message-text-fail {
    color: #f56c6c;
  }
  .verify-code-message-text-wait {
    color: rgb(102, 102, 102);
  }

  .verify-code-button-basic {
    width: 100%;
    overflow: hidden;
    margin-top: 96px;
    display: flex;
    justify-content: center;
  }
  .verify-code-button-basic>button {
    font-size: 16px;
    margin: 0 16px;
    border: none;
    padding: 6px 42px;
    border-radius: 3px;
    color: white;
    cursor: pointer;
  }

  .verify-code-button-basic .submit {
    background-color: #409eff;
  }
  .verify-code-button-basic .reset {
    background-color: #909399;
  }

  .common-opacity-1-animation {
    animation-name: opacity1Animation;
    animation-duration: .6s;
    animation-fill-mode: forwards;
  }
  .common-opacity-2-animation {
    display: none;
    animation-name: opacity2Animation;
    animation-duration: .6s;
    animation-fill-mode: forwards;
  }

  @keyframes opacity1Animation {
    from {
      opacity: 0;
    }
    to{
      opacity: 1;
    }
  }
  @keyframes opacity2Animation {
    from {
      display: flex;
      opacity: 1;
    }
    to{
      opacity: 0;
    }
  }

</style>